use std::{fmt, fmt::Display};
#[derive(Debug)]
pub struct KidsGift {
    pub name: String,
}

impl Display for KidsGift {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.name)
    }
}
#[derive(Debug)]
pub struct ElvesGift {
    pub name: String,
}

impl Display for ElvesGift {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.name)
    }
}
#[derive(Debug)]
pub struct ReindeerGift {
    pub name: String,
}

impl Display for ReindeerGift {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.name)
    }
}

/* // use marco to write impl display

macro_rules! impl_display_with_name {
    ($type_name: ty) => {
        impl Display for $type_name {
            fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
                write!(f, "{}", self.name)
            }
        }
    }
}
impl_display_with_name!(KidsGift);
impl_display_with_name!(ElvesGift);
impl_display_with_name!(ReindeerGift);

*/

pub fn display_gift<T: fmt::Display>(gift: T) {
    println!("{}", gift);
}

/*
pub fn display_gift(gift: impl fmt::Display) {
    println!("{}", gift);
}
*/

pub fn main() {
    let kids_gift = KidsGift {
        name: "toy car".to_string(),
    };
    let elves_gift = ElvesGift {
        name: "vertical monitor".to_string(),
    };
    let reindeer_gift = ReindeerGift {
        name: "carrot".to_string(),
    };

    display_gift(&kids_gift);
    display_gift(&elves_gift);
    display_gift(&reindeer_gift);
}
